/**表达式编辑器js
 * 吕凯 2021-2-23 10:35:42
 *  */
;(function($){
	$.fn.expression = function(options){
		var spacename = ".expression_";
		var innerEleSelector = ".expressionEle";
		if (options == null) {
			options = {};
        }
		
        options = $.extend({}, $.fn.expression.defaultOptions, options);
        options.ar
		var eles = $(this); //表单
		eles.each(function(){
			var $this = $(this);
			var target = $this.data("target"); // 表达式储存的元素
			var value = $this.data("value"); //表达式的默认值
			
			var argsTitle = $this.find(".innerArg_title"); //内置变量说明标签
			if(argsTitle.length == 0){ //没有则创建
				argsTitle = $('<div class="innerArg_title" ></div>');
				$this.prepend(argsTitle);
            }
			
			var argsContainer = $this.find(".innerArg_container"); //内置变量容器
			showContainer = $('<div class="innerArg_container" ></div>');
			if(argsContainer.length == 0 ){
				argsTitle.after(showContainer); //插入到说明标签后面
            }
			if (!argsContainer.html().trim()) { //如果内容为空，则插入变量
				createArgEle(argsContainer, options.args);
            } 
			//覆盖变量
			options.args = parseArgs (argsContainer);
			options.sortargs = sortArgs(options.args);
			
			var showContainer = $this.find(".expressionShow");
			if(showContainer.length == 0){ //没有则创建
				showContainer = $('<div contenteditable="true" tabindex="1" class="expressionShow" >'+value+'</div>');
				$this.append(showContainer);
			}
			// 表达式解释器容器
			var explainContainer = $this.find(".expressionExplain");
			if(explainContainer.length == 0){ //没有则创建
				explainContainer = $('<div class="expressionExplain" title="表达式解释说明" ></div>');
				$this.append(explainContainer);
			}
			
			// 保存选中区域
			showContainer.off('mouseup'+spacename).on('mouseup'+spacename, function(e){
		    	saveSelection(showContainer);
		    });
			showContainer.off('keyup'+spacename).on('keyup'+spacename,function(e){
		    	saveSelection(showContainer);
		    });
			
			// 变量元素，点击事件
			argsContainer.find(".innerArg").off('click'+spacename).on("click"+spacename, function(){
				var $this = $(this);
				var value = $this.attr("ev");
				var name = $this.text()||$this.val();
				var desp = $this.attr("title")||value;
				var visNumber = isNumber(value);
				
				//var htmlVal = '<span class="expressionEle">' + value + '<a class="close" href="javascript:void(0);"></a></span>';
				var htmlVal = '<span title="'+name+'" desp="'+desp+'" class="expressionEle '+(visNumber?'number':'')+'">' + value + '</span>';
				insertContent(showContainer, htmlVal);
				showContainer.data("target", target);
				showContainer.triggerHandler("change");
				return false;
			});
			// 展示容器，自定义change事件
			showContainer.off('change'+spacename).on('change'+spacename, function(e){
				var $this = $(this);
				var expressionVal = $this.text().trim();
				if (target) {
					getjQueryObj(target).val(expressionVal);
                }
				explainExpress(explainContainer, showContainer); //解释表达式
			});
			var targetEle;
			if (target) {
				targetEle = getjQueryObj(target);
				// 处理表单重置事件
				targetEle.off('reset'+spacename).on('reset'+spacename, function(e){
					var $this = $(this);
					$this.val(value);
					// 解析表达式为html格式
					parseExpress(options.sortargs, showContainer, value);
					explainExpress(explainContainer, showContainer); // 解释表达式
				});
            }
			// 展示容器，处理按键监听
			showContainer.off('keydown'+spacename).on('keydown'+spacename, function(e){
				var $this = $(this);
				var key = e.which;
				var continueRun = true;
		     	if (key == Touchjs.keyCode.BACKSPACE) { //删除键 8
		     		var containerEle = $(this);
		 		    var selectedEles = containerEle.children(".selected");
		 		    if (selectedEles.length > 0) { //选中元素
		 		    	selectedEles.remove();
		 		    	continueRun = false;
		 		    } else {
		 		    	var htmlBeforeCursor = getTextBeforeCursor(showContainer[0]);
		         		var frag=htmlBeforeCursor[0];
				    	var range=htmlBeforeCursor[1];
		         		console.log(frag);
						if (!-[1,]) {
					         var last_node = $(frag)[0].lastChild; //文本
						} else {
					         var last_node = frag.lastChild;
						}
						if (last_node != null && last_node.nodeType==3 && last_node.nodeValue=="") {//空字符串处理
							last_node=last_node.previousSibling;
						}
						if (last_node.nodeType==1 && last_node.nodeName=='SPAN') {
							$(frag).css("border", "1px solid red")
							frag.removeChild(last_node)
							range.deleteContents();
							var div = document.createElement('div');
							div.appendChild(frag);
							document.execCommand("insertHtml", false, div.innerHTML);
							div = null;
							// $('editor').insertBefore(frag,$('editor').childNodes[0])
							e.preventDefault();
							dealInnerEle(containerEle);
					        //$(a).remove();
						} 
		 		    }
				} else if(key == Touchjs.keyCode.LEFT) { // 左 37
					
				} else if(key == Touchjs.keyCode.RIGHT) { // 右 39
					
				} else { //禁止输入
					continueRun = false;
				}
		     	$this.triggerHandler("change");
				return continueRun;
		    });
			// ===============展示容器内部元素事件 begin=============
			// 点击内部元素则设为选中状态
			showContainer.off('click'+spacename, innerEleSelector).on("click"+spacename, innerEleSelector, function() {
		 		$(this).addClass("selected");
		 		return false;
			});
			// 鼠标移入，显示删除
			showContainer.off('mouseenter'+spacename, innerEleSelector).on("mouseenter"+spacename, innerEleSelector, function() {
				var $this = $(this);
				$this.addClass("expression-hover").append('<a class="close" title="点击删除，也可使用删除键删除" href="javascript:void(0);"></a>');
			});
			// 鼠标移出，去除删除
			showContainer.off('mouseleave'+spacename, innerEleSelector).on("mouseleave"+spacename, innerEleSelector, function() {
				var $this = $(this);
				$this.removeClass("expression-hover").find(".close").remove();
			});
			// 点击内部元素的删除按钮
			showContainer.off('click'+spacename, ".close").on("click"+spacename, ".close", function() {
		 		var $this = $(this);
		 		$this.closest(innerEleSelector).remove();
		 		showContainer.triggerHandler("change");
			});
			
			//点击空白取消选中
			$(document).off('click'+spacename).on("click"+spacename, function() { 
		 		showContainer.find(innerEleSelector).removeClass("selected");
			});
			// ===============展示容器内部元素事件 end =============
			// 解析表达式为html格式
			parseExpress(options.sortargs, showContainer);
			explainExpress(explainContainer, showContainer); // 解释表达式
		});
	}
	
	//覆盖变量
	function parseArgs (argsContainer){ 
    	var args = new Array();
    	argsContainer.find(".innerArg").each(function(i, n){
    		var $this = $(this);
			var name = $this.text();
			var value = $this.attr("ev")||name;
			var desp = $this.attr("title")||name;
			var argsIn = new Array();
			argsIn.push(name);
			argsIn.push(value);
			argsIn.push(desp);
			args.push(argsIn);
		});
    	return args;
    }
	
	// 变量排序，返回变量的副本，不修改原变量
	function sortArgs (args){ 
		var argsCopy = $.extend(true, [], args);
		argsCopy.sort(function(a,b){
			return b[1].length - a[1].length; //长度长的在前面
		})
		return argsCopy;
	}
	
	
	var currentRange, _parentElem, supportRange = typeof document.createRange === 'function';
	function getCurrentRange(ele) {
		var selection, range, txt = ele;
		if (supportRange) {
            selection = document.getSelection();
            if (selection.getRangeAt && selection.rangeCount) {
            	range = document.getSelection().getRangeAt(0);
            	_parentElem = range.commonAncestorContainer;
            }
        } else {
            range = document.selection.createRange();
            _parentElem = range.parentElement();
        }
        if ( _parentElem && (txt.find(_parentElem) || txt === _parentElem) ) {
        	parentElem = _parentElem;
        	return range;
        }
        return range;
    }
    function saveSelection(ele) {
    	currentRange = getCurrentRange(ele);
    }
    function restoreSelection() {
    	if(!currentRange){
    		return;
    	}
    	var selection, range;
    	if(supportRange){
    		selection = document.getSelection();
    		selection.removeAllRanges();
    		selection.addRange(currentRange);
    	}else{
            range = document.selection.createRange();
            range.setEndPoint('EndToEnd', currentRange);
            if(currentRange.text.length === 0){
            	range.collapse(false);
            }else{
            	range.setEndPoint('StartToStart', currentRange);
            }
            range.select();
        }
    }
	 	
 	// 获取光标前的文本，getTextBeforeCursor的作用是获取光标前的内容.由于兼容性，这个函数在标准浏览器中可以得到是光标前所有内容的DocumentFragment，
 	// 而在ie中就只能得到文本(不是node)了，不过这个html字符串可以转换成DocumentFragment.	jquery中用$(html)[0]也能得到node.
	// 有了这个函数，再用lastChild就可以判断光标是不是在光标前html的lastChild里，并且这个lastChild是span。 
	function getTextBeforeCursor(containerEl) {
         var precedingChar = "", sel, range, precedingRange;
         if (window.getSelection) {
             sel = window.getSelection();
             if (sel.rangeCount > 0) {
                 range = sel.getRangeAt(0).cloneRange();
                 range.collapse(true);
                 range.setStart(containerEl, 0);
                 precedingChar = range.cloneContents();
             }
         } else if ( (sel = document.selection)) {
             range = sel.createRange();
             precedingRange = range.duplicate();
             precedingRange.moveToElementText(containerEl);
             precedingRange.setEndPoint("EndToStart", range);
             precedingChar = precedingRange.htmlText;
         }
         return [precedingChar,range];
	}
	
	// 创建变量元素
	function createArgEle(ele, args){
		var html = '';
		for (var i = 0; i < args.length; i++) {
			var argsArrs = args[i]; //包含3列，分别为名称、值、说明，后两项可能为空，如果只有一个则说明三个值合一了
		    if (argsArrs== "|" || argsArrs=="separator") {// 分组
		    	html += '<br/>';
            } else {
            	var name = argsArrs[0];
            	var value = argsArrs[1] ? argsArrs[1] : name;
            	var desp = argsArrs[2] ? argsArrs[2] : name;
            	html += '<button title="'+desp+'" ev="'+value+'" class="btn-blue innerArg" >'+name+'</button>';
            }
        }
		ele.html(html);
	}
	
	/**
	* 校验只要是数字（包含正负整数，0以及正负浮点数）就返回true
	**/
	function isNumber(val){
	    var regPos = /^-?\d+(\.\d+)?$/; //正负整数或浮点数
	    if(regPos.test(val)){
	        return true;
	    }else{
	        return false;
	    }
	}
	
	//在光标位置插入内容
	function insertContent(ele, content) {
	    if (!content) {//如果插入的内容为空则返回
	        return;
	    }
	    var containerEle = ele; // $("#expressionShow");
	    var selectedEles = containerEle.children(".selected");
	    if (selectedEles.length > 0) {
	    	selectedEles.each(function(i, n){
	    		var selectEle = $(this);
	    		if (i==0) { //只替换第一个，后面的替换为空字符串
	    			selectEle.replaceWith(content);
	    		} else {
	    			selectEle.replaceWith("");
	    		}
	    	});
	    	
	    } else {
		    var sel = null;
		    if (document.selection) {//IE9以下
		        sel = document.selection;
		        sel.createRange().pasteHTML(content);
		    } else {
		        sel = window.getSelection();
		        if (sel.rangeCount > 0) {
		            var range = sel.getRangeAt(0);      //获取选择范围
		            range.deleteContents();             //删除选中的内容
		            var el = document.createElement("div"); //创建一个空的div外壳 
		            el.innerHTML = content;                 //设置div内容为我们想要插入的内容。
		            var frag = document.createDocumentFragment();//创建一个空白的文档片段，便于之后插入dom树

		            var node = el.firstChild;
		            var lastNode = frag.appendChild(node);
		            range.insertNode(frag);					//设置选择范围的内容为插入的内容
		            var contentRange = range.cloneRange();	//克隆选区
		            contentRange.setStartAfter(lastNode);	//设置光标位置为插入内容的末尾
		            contentRange.collapse(true);	//移动光标位置到末尾
					sel.removeAllRanges();			//移出所有选区
					sel.addRange(contentRange);		//添加修改后的选区
					
				}
			}
	    }
	    // 插入到内部了
	    dealInnerEle(containerEle);
	}
	
	// 处理内部嵌套元素
	function dealInnerEle(containerEle) { //需要处理的jq节点对象
		var expressionElesL1 = containerEle.children(".expressionEle");
	    if (expressionElesL1.length > 0) {
		    expressionElesL1.each(function(){
		    	var $this = $(this);
		    	var expressionElesL2 = $this.children(".expressionEle");
		    	if(expressionElesL2.length > 0){
		    		$this.after(expressionElesL2);
		    	}
		    	if(!$this.text().trim()){
		    		$this.remove();
		    	}
		    });
		    placeCaretAtEnd(containerEle[0]);
	    }
	}
	// 光标移到最后
	function placeCaretAtEnd(el) { //传入光标要去的jq节点对象
	   /*  console.log(el)
	    console.log(window.getSelection)
	    console.log(document.selection) */
	    if (window.getSelection) { //ie11 10 9 ff safari
	    	//el.focus(); //解决ff不获取焦点无法定位问题
	        var range = window.getSelection(); //创建range
	        range.selectAllChildren(el); //range 选择ev下所有子内容
	        range.collapseToEnd(); //光标移至最后
	    } else if (document.selection) { //ie10 9 8 7 6 5
	        var range = document.selection.createRange(); //创建选择对象
	        //var range = document.body.createTextRange();
	        range.moveToElementText(el); //range定位到ev
	        range.collapse(false); //光标移至最后
	        range.select();
	    }
	}
	
	function isGroupSeparator(value){
		return value == "|" || value =="separator"; // 分组
	}
	
	// 解析表达式
	var parseExpress = function(args, showEle, expression){
		if (!expression) { //如果没有传入表达式，则取元素里面的内容
			expression = showEle.text();
        }
		console.log("args=======");
		console.log(args);
		var myExps = new Array();
		myExps.push([expression, expression, expression]) //  包含3列，分别为值、名称、说明，后两项可能为空，如果只有一个则说明三个值合一了
		splitExpression(myExps, args, 0);
		//console.log("处理后的数组");
		//console.log(myExps);
		
		var htmlValue = "";
		for (var i = 0; i < myExps.length; i++) {
			var name = myExps[i][0];
			var value = myExps[i][1] ? myExps[i][1] : name;
			var desp = myExps[i][2] ? myExps[i][2] : name;
			var visNumber = isNumber(value);
			htmlValue += '<span title="'+name+'" desp="'+desp+'" class="expressionEle '+(visNumber?'number':'')+'">' + value + '</span>';
        }
			
		showEle.html(htmlValue);
		return myExps;
	}
	// 解释表达式为容易理解的说明
	var explainExpress = function(explainContainer, showContainer){
		var html = "";
		showContainer.find(".expressionEle").each(function() {
			var $this = $(this);
			html += $this.attr("title");
        });
		explainContainer.html(html);
	}
	 
	
	/**
	 * 分解数组里的表达式
	 */
	function splitExpression(myExps, args, index){
		var startIndex = index, endIndex = index;
		for (var i = 0; i < args.length; i++) {
			var argsArrs = args[i]; // 包含3列，分别为名称、值、说明，后两项可能为空，如果只有一个则说明三个值合一了
			if (!isGroupSeparator(argsArrs)) {// 非分组符号
				var name = argsArrs[0];
				var value = argsArrs[1] ? argsArrs[1] : name;
				var desp = argsArrs[2] ? argsArrs[2] : name;
				var parExpression = myExps[index][0];
				if (parExpression.indexOf(value) > -1) {
					var varrs = parExpression.split(value);
					// 分为3部分，当前元素符合的部分，前面，后面，符合部分不需要再解析了，前面后面需要再次解析
					var value0 = varrs[0];
					var value1 = varrs[1];

					if (varrs.length > 2) { // 超过2项后面的合并
						var varrsConcat = $.extend(true, [], varrs);
						varrsConcat.shift(); // 移除第一个元素
						value1 = varrsConcat.join(value);
					}
					if (value0 != "") {
						myExps.splice(startIndex, 0, [value0, value0, value0]); // 添加到前面
						index++;
					}
					myExps.splice(index, 1, [name, value, desp]); // 替换
					if (value1 != "") {
						endIndex = ++index;
						myExps.splice(index, 0, [value1, value1, value1]); // 添加到后面
					}
//					console.log("myExps====" + value)
//					console.log(myExps)
					// 后面部分继续解析
					if (value1 != "") {
						splitExpression(myExps, args, endIndex);
					}
					// 前面部分继续解析
					if (value0 != "") {
						splitExpression(myExps, args, startIndex);
					}

					break;
				}
			}
		}
		return endIndex;
	}
	
	//默认参数
    $.fn.expression.defaultOptions = {
    	/**	内置变量,分别为名称，值，说明 */
		args : [
			["1","1"] 
		    ,["2","2"] 
		    ,["3", "3"] 
		    ,["4", "4"] 
		    ,["5", "5"]
		    ,["6"] 
		    ,["7"] 
		    ,["8"] 
		    ,["9"] 
		    ,["0"] 
		    ,["+"]
		    ,["-"]
		    ,["×","*","乘以"]
		    ,["÷","/","除以"]
		],
		/**	提交的字段名称,未使用 */
		key : 'k'
    };
})(jQuery);
